package io.task.message.socket.maintain;

import io.task.message.socket.ChannelContext;
import io.task.message.socket.Config;
import io.task.message.socket.lock.LockUtils;
import io.task.message.socket.lock.MapWithLock;
import io.task.message.socket.lock.SetWithLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.HashSet;

/**
 * 一对多  (ip <--> ChannelContext)<br>
 * 一个ip有哪些客户端，该维护只在Server侧有<br>
 */
public class Ips {

    /**
     * The log.
     */
    private static final Logger log = LoggerFactory.getLogger(Ips.class);

    /**
     * 一个IP有哪些客户端
     * key: ip
     * value: SetWithLock<ChannelContext>
     */
    private final MapWithLock<String, SetWithLock<ChannelContext>> ipmap = new MapWithLock<>(new HashMap<String, SetWithLock<ChannelContext>>());
    private final String rwKey = "_tio_ips__";

    /**
     * 和ip绑定
     */
    public void bind(ChannelContext channelContext) {
        if (channelContext == null) {
            return;
        }


        try {
            String ip = channelContext.getClientNode().getIp();


            SetWithLock<ChannelContext> channelSet = ipmap.get(ip);
            if (channelSet == null) {
                LockUtils.runWriteOrWaitRead(rwKey + ip, this, () -> {

                    if (ipmap.get(ip) == null) {
//							channelSet = new SetWithLock<>(new HashSet<ChannelContext>());
                        ipmap.put(ip, new SetWithLock<>(new HashSet<ChannelContext>()));
                    }
//					}
                });
                channelSet = ipmap.get(ip);
            }
            channelSet.add(channelContext);
        } catch (Exception e) {
            log.error(e.toString(), e);
        }
    }

    /**
     * 一个ip有哪些客户端，有可能返回null
     */
    public SetWithLock<ChannelContext> clients(Config config, String ip) {


        return ipmap.get(ip);
    }


    /**
     * 与指定ip解除绑定
     */
    public void unbind(ChannelContext channelContext) {
        if (channelContext == null) {
            return;
        }


        try {
            String ip = channelContext.getClientNode().getIp();


            SetWithLock<ChannelContext> channelSet = ipmap.get(ip);
            if (channelSet != null) {
                channelSet.remove(channelContext);
                if (channelSet.size() == 0) {
                    ipmap.remove(ip);
                }
            } else {
                log.info("{}, ip【{}】 找不到对应的SetWithLock", channelContext.config.getName(), ip);
            }
        } catch (Exception e) {
            log.error(e.toString(), e);
        }
    }
}
